﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Drawing;
using System.Windows.Forms;
using System.Threading;

namespace Adaptive_Clustering
{
    public class MainController
    {
        protected int BestKindex;
        protected Bitmap image, imageResult;
        protected MainGUI M_GUI;
           
        public MainController()
        {
        }

        public void ResetImage()
        {           
                image = null;
                imageResult = null;
                M_GUI.Selected_Image_PctBx.Image = image;
                M_GUI.Result_Image_PctBx.Image = imageResult;            
        }
        
        public void SetGUI(MainGUI M_GUI)
        {
            this.M_GUI = M_GUI;
        }
        
        public int GetBestKindex() { return BestKindex; }

        public bool ImageIsLoaded()
        {
            if (image == null) return false;
            else return true;
        }

        public void LoadImage(String s_path)
        {
            try
            {
                image = new Bitmap(s_path);
                
                M_GUI.Selected_Image_PctBx.SizeMode = PictureBoxSizeMode.StretchImage;
                M_GUI.Selected_Image_PctBx.Image = image;
            
                int DesieredWidth = 300;
                float ImageRatio;
                if (image.Height < image.Width)
                {
                    ImageRatio = image.Height / (float)image.Width;
                    image = ResizeImage(image, DesieredWidth, (int)(DesieredWidth * ImageRatio));
                }
                else
                {
                    ImageRatio = image.Width / (float)image.Height;
                    image = ResizeImage(image, (int)(DesieredWidth * ImageRatio), DesieredWidth);
                }
            }
            catch
            {
                MessageBox.Show("Image loading Failed.", "Error!", MessageBoxButtons.OK);
            }

            
        }

        public bool ImageIsProccessed()
        {
            if (imageResult != null)            
                return true;            
            else
                return false;
        }

        public void SaveImage(String p)
        {
            imageResult.Save(p);
        }
        
        public int ImageWidth
        {
            get
            {
                if (image.Width > 0)
                    return image.Width;
                else return 0;
            }
        }
        
        public int ImageHeight
        {
            get
            {
                if (image.Height > 0)
                    return image.Height;
                else return 0;
            }
        }

        public ResultImage[] ProccessImage(int k, int MinK, int Sigma, int Beta, bool MarkMaxSx, Color MarkColor,bool EnableBilinear)//,Thread oThread)
        {
            //---------------------//
            //----initilization----//
            //---------------------//


            ResultImage[] ResultImages = new ResultImage[k + 1];
            for (int i = 0; i < ResultImages.Length; i++)
                ResultImages[i] = new ResultImage();
            Byte[,] ImageArray = new Byte[image.Width, image.Height];
            ImageArray = GrayScale(image);
            Byte[,] ImageClusterIndexArray;
            for (int kCounter = MinK; kCounter < k + 1; kCounter++) //Model Selection
            {
                //------------------------//
                //---Kmeans first stage---//
                //------------------------//
                Byte[,] TempImageArray;
                KMeans kmns = new KMeans(ImageArray, kCounter, M_GUI);
                ImageClusterIndexArray = kmns.GetImageClusterIndexArray();
                TempImageArray = kmns.GetImageArray();
                //---------------------//
                //---advanced Kmeans---//
                //---------------------//
               
                Adaptive adpt = new Adaptive(TempImageArray, ImageClusterIndexArray, kCounter, Sigma, Beta, M_GUI, EnableBilinear);
                adpt.Adapt();
                ResultImages[kCounter].SaveImage(adpt.GetImageArray(), adpt.GetImageClusterIndexArray(), kCounter);
            }
            //-----------------------//
            //----Model Selection----//
            //-----------------------//
            BestKindex = MinK;
            double BestKsx = ResultImages[MinK].GetBestSxIndexValue();
            for (int kCounter = MinK + 1; kCounter < ResultImages.Length; kCounter++)
                if (ResultImages[kCounter].GetBestSxIndexValue() > BestKsx)
                {
                    BestKsx = ResultImages[kCounter].GetBestSxIndexValue();
                    BestKindex = kCounter;
                }
            ImageArray = ResultImages[BestKindex].GetImageArray();
            ImageClusterIndexArray = ResultImages[BestKindex].GetImageClusterIndexArray();
            //---------------------//
            //----back to image----//
            //---------------------//
            int MaxSxIndex = ResultImages[BestKindex].GetBestSxIndex();

            DisplayImage(ImageArray, ImageClusterIndexArray, MarkMaxSx, BestKindex, MaxSxIndex, MarkColor);
            return ResultImages;
        }

        public static Bitmap ResizeImage(Bitmap sourceBmp, int width, int height)
        {
            Bitmap result = new Bitmap(width, height);
            using (Graphics g = Graphics.FromImage(result))
                g.DrawImage(sourceBmp, 0, 0, width, height);
            return result;
        }

        public void DisplayImage(Byte[,] ImageArray, Byte[,] ImageClusterIndexArray, bool MarkMaxSx, int BestKindex, int MaxSxIndex, Color MarkColor)
        {
            imageResult = ConvertByteToBitmap(ImageArray);
            if (MarkMaxSx)
            {
                int i_luma;
                Color newColor;
                for (int i = 0; i < ImageArray.GetLength(0); i++)//paint the tightest cluster (main figure)
                    for (int j = 0; j < ImageArray.GetLength(1); j++)
                        if (ImageClusterIndexArray[i, j] == MaxSxIndex)
                        {
                            i_luma = (int)ImageArray[i, j];
                            newColor = Color.FromArgb(MarkColor.R, MarkColor.G, MarkColor.B);
                            imageResult.SetPixel(i, j, newColor);
                        }
            }
            M_GUI.UpadteImage(imageResult);
         }     

        private Byte[,] GrayScale(Bitmap image)
        {
            int i_BlueColor, i_GreenColor, i_RedColor, i_luma;
            Color pixelColor;
            Byte[,] ImageArray;
            ImageArray = new Byte[image.Width, image.Height];
        
            double ProgressRatio = (double)(Constants.ProgressBarGrayScale / (double)ImageWidth);
            double ProgressCounter = M_GUI.ProcessImageProgressBar % Constants.ProgressBarMaxVal;
        
            // convert to grayscale
            for (int x = 0; x < image.Width; x++)
            {
                for (int y = 0; y < image.Height; y++)
                {
                    pixelColor = image.GetPixel(x, y);
                    i_RedColor = (int)(pixelColor.R * 0.2126);
                    i_GreenColor = (int)(pixelColor.G * 0.7152);
                    i_BlueColor = (int)(pixelColor.B * 0.0722);
                    i_luma = i_RedColor + i_GreenColor + i_BlueColor;
                    ImageArray[x, y] = (Byte)i_luma;
                }
               
                ProgressCounter += ProgressRatio;
                M_GUI.ProcessImageProgressBar = (int)(ProgressCounter % Constants.ProgressBarMaxVal);
            
            }
            return ImageArray;
        }

        private Bitmap ConvertByteToBitmap(Byte[,] ImageArray)
        {
            int i_luma;
            int imageWidth = ImageArray.GetLength(0);
            int imageHeight = ImageArray.GetLength(1);
            Color newColor;
            Bitmap img = new Bitmap(imageWidth, imageHeight);
            double ProgressRatio = (double)(Constants.ProgressBarConvertByteToBitmap / imageWidth);
            double ProgressCounter = M_GUI.ProcessImageProgressBar % Constants.ProgressBarMaxVal;
            //convert to image type
            for (int x = 0; x < imageWidth; x++)
            {
                for (int y = 0; y < imageHeight; y++)
                {
                    i_luma = (int)ImageArray[x, y];
                    newColor = Color.FromArgb(i_luma, i_luma, i_luma);
                    img.SetPixel(x, y, newColor);
                }
                ProgressCounter += ProgressRatio;
                M_GUI.ProcessImageProgressBar = (int)(ProgressCounter % Constants.ProgressBarMaxVal);                         
            }
            return img;
        }
    }
}




